package cn.iocoder.yudao.module.book.service.app;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.book.controller.app.vo.AppBookReadingProgramItemRespVO;
import cn.iocoder.yudao.module.book.controller.app.vo.AppBookReadingProgramReqVO;
import cn.iocoder.yudao.module.book.controller.app.vo.AppBookReadingProgramRespVO;
import cn.iocoder.yudao.module.book.dal.dataobject.book.BookDO;
import cn.iocoder.yudao.module.book.dal.dataobject.readingprogram.ReadingProgramDO;
import cn.iocoder.yudao.module.book.dal.dataobject.readingprogramitem.ReadingProgramItemDO;
import cn.iocoder.yudao.module.book.dal.mysql.readingprogram.ReadingProgramMapper;
import cn.iocoder.yudao.module.book.dal.mysql.readingprogramitem.ReadingProgramItemMapper;
import cn.iocoder.yudao.module.book.service.admin.book.BookService;
import cn.iocoder.yudao.module.book.service.admin.bookshelf.BookShelfService;
import jakarta.annotation.Resource;

@Service
public class AppBookReadingProgramServiceImpl implements AppBookReadingProgramService {

    @Resource
    private ReadingProgramItemMapper bookReadingProgramItemMapper;
    @Resource
    private ReadingProgramMapper     bookReadingProgramMapper;
    @Resource
    private BookService              bookService;
    @Resource
    private BookShelfService         bookShelfService;

    @Override
    public List<AppBookReadingProgramRespVO> getBookReadingProgramList(String type) {
        LambdaQueryWrapper<ReadingProgramDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReadingProgramDO::getUserId,SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.eq(ReadingProgramDO::getCatalogue, type);
        queryWrapper.orderByDesc(ReadingProgramDO::getCreateTime);
        List<ReadingProgramDO> bookReadingProgramDOList = bookReadingProgramMapper.selectList(queryWrapper);
        if (bookReadingProgramDOList != null && !bookReadingProgramDOList.isEmpty()) {
            return BeanUtils.toBean(bookReadingProgramDOList, AppBookReadingProgramRespVO.class);
        }
        return List.of();
    }

    @Override
    public AppBookReadingProgramRespVO getBookReadingProgramById(Long id) {
        ReadingProgramDO bookReadingProgramDO = bookReadingProgramMapper.selectById(id);

        AppBookReadingProgramRespVO bookReadingProgramRespVO = BeanUtils.toBean(bookReadingProgramDO,
            AppBookReadingProgramRespVO.class);
        List<ReadingProgramItemDO> bookReadingProgramItemDOList =
            bookReadingProgramItemMapper.selectList(new QueryWrapperX<ReadingProgramItemDO>()
                .eq("book_reading_program_id", id)
                .orderByDesc("days"));
        List<AppBookReadingProgramItemRespVO> bookReadingProgramItemRespVOList =
            BeanUtils.toBean(bookReadingProgramItemDOList, AppBookReadingProgramItemRespVO.class);
        if (bookReadingProgramItemRespVOList != null && !bookReadingProgramItemRespVOList.isEmpty()) {
            bookReadingProgramItemRespVOList.forEach(item -> {
                String[] bookIds = item
                    .getBookIds()
                    .split("_");
                List<BookDO> bookDOList = new ArrayList<>();
                for (String bookId : bookIds) {
                    BookDO bookDO =
                        bookService.getBook(Long.valueOf(bookId));
                    if (bookDO != null) {
                        bookDOList.add(bookDO);
                        item.setBookDO(bookDOList);
                    }
                }
            });
            bookReadingProgramRespVO.setBookReadingProgramItemRespVOList(bookReadingProgramItemRespVOList);
        }
        return bookReadingProgramRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBookReadingProgram(AppBookReadingProgramReqVO createReqVO) {
        ReadingProgramDO bookReadingProgramDO = BeanUtils.toBean(createReqVO, ReadingProgramDO.class);
        int bookCount = 0;
        int totalDays = 0;
        List<BookDO> allBooks = new ArrayList<>();
        if (createReqVO.getPlanType() == 1) {
            // 根据绘本集ID查询对应的绘本列表
            String[] bookShelfIds = createReqVO
                .getBookShelfIds()
                .split("_");
            // 1. 拉平书籍

            for (String bookShelfId : bookShelfIds) {
                allBooks.addAll(Optional
                    .ofNullable(bookService.getBookShelfIdByList(Long.valueOf(bookShelfId)))
                    .orElse(Collections.emptyList()));
            }
            bookCount = allBooks.size();
            if (bookCount == 0) {
                bookReadingProgramDO.setPlannedDays(0);
                return bookReadingProgramDO.getId();
            }

            // 2. 总天数固定
            if (allBooks.size() > 6) {
                totalDays = bookCount - 1;
            } else {
                totalDays = bookCount;
            }
        } else {
            totalDays = createReqVO
                .getBookReadingProgramItemRespVOList()
                .size();
            bookReadingProgramDO.setLearnAFewNewThingsEveryDay(totalDays);
            bookReadingProgramDO.setReviewFrequency("0");
        }

        bookReadingProgramDO.setPlannedDays(totalDays);
        bookReadingProgramDO.setUserId(SecurityFrameworkUtils.getLoginUserId());
        bookReadingProgramMapper.insert(bookReadingProgramDO);

        List<ReadingProgramItemDO> itemList = new ArrayList<>();
        if (createReqVO.getPlanType() == 1) {
            // 3. 固定复习日模板
            List<Integer> template = Arrays.asList(2, 5, 8, 16, 31);
            List<Integer> reviewOffsets =
                template.subList(0, Math.min(createReqVO.getReviewFrequency(), template.size()));

            // 4. 生成每天明细
            for (int dayNo = 1; dayNo <= totalDays; dayNo++) {
                Set<Long> dayBookIds = new LinkedHashSet<>();
                // 4-1 当天新书（第 dayNo 本，索引从 0 开始）
                dayBookIds.add(allBooks
                    .get(dayNo - 1)
                    .getId());
                // 4-2 复习书：对每本书计算其复习日
                for (int bookIdx = 0; bookIdx < bookCount; bookIdx++) {
                    for (int offset : reviewOffsets) {
                        int reviewDay = bookIdx + offset;
                        if (reviewDay == dayNo) {
                            dayBookIds.add(allBooks
                                .get(bookIdx)
                                .getId());
                        }
                    }
                }
                // 4-3 拼接
                String idsStr = dayBookIds
                    .stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining("_"));

                ReadingProgramItemDO item = new ReadingProgramItemDO();
                item.setBookReadingProgramId(bookReadingProgramDO.getId());
                item.setDays(dayNo);
                item.setBookIds(idsStr);
                item.setUserId(SecurityFrameworkUtils.getLoginUserId());
                itemList.add(item);
            }
        } else {
            itemList = BeanUtils.toBean(createReqVO.getBookReadingProgramItemRespVOList(), ReadingProgramItemDO.class);
            if (CollUtil.isNotEmpty(itemList)) {
                itemList.forEach(item -> {
                    item.setUserId(SecurityFrameworkUtils.getLoginUserId());
                    item.setBookReadingProgramId(bookReadingProgramDO.getId());
                });
            }
        }

        // 5. 批量插入
        if (!itemList.isEmpty()) {
            bookReadingProgramItemMapper.insertBatch(itemList);
        }
        return 0L;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBookReadingProgram(AppBookReadingProgramReqVO updateReqVO) {
        ReadingProgramDO bookReadingProgramDO = BeanUtils.toBean(updateReqVO, ReadingProgramDO.class);
        bookReadingProgramMapper.updateById(bookReadingProgramDO);
        List<ReadingProgramItemDO> bookReadingProgramItemDOList =
            bookReadingProgramItemMapper.selectList(new QueryWrapperX<ReadingProgramItemDO>().eq(
                "book_reading_program_id", updateReqVO.getId()));
        List<ReadingProgramItemDO> itemList =
            BeanUtils.toBean(updateReqVO.getBookReadingProgramItemRespVOList(), ReadingProgramItemDO.class);
        for (ReadingProgramItemDO item : itemList) {
            boolean updated = false;
            for (ReadingProgramItemDO dbItem : bookReadingProgramItemDOList) {
                if (item.getId() != null && item
                    .getId()
                    .equals(dbItem.getId())) {
                    bookReadingProgramItemMapper.updateById(item);
                    updated = true;
                    break; // 跳出第二层循环
                }
            }
            if (!updated) {
                // id 为空或数据库不存在，则插入
                bookReadingProgramItemMapper.insert(item);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBookReadingProgram(Long id) {
        bookReadingProgramMapper.deleteById(id);
        bookReadingProgramItemMapper.delete(new QueryWrapperX<ReadingProgramItemDO>().eq("book_reading_program_id",
            id));
    }
}
